// // Copyright (c) 2009 All Right Reserved // // vl // // 2009-02-01 // using System; using System.Diagnostics.Contracts; using System.Text; using LargoCommon.Abstract; using LargoCommon.Music; namespace LargoCommon.Composer { /// /// MusicPiece Sequence. /// public class MusicalSequence { #region Fields /// /// Melodic Variety. /// private readonly MusicalVariety melodicVariety; /// /// Melodic Shape. /// private readonly MelodicShape melodicShape; /// /// Harmonic System. /// private HarmonicSystem harmonicSystem; #endregion #region Constructors /// /// Initializes a new instance of the class. /// /// The given variety. public MusicalSequence(MusicalVariety givenVariety) { //// Warning 4 CodeContracts: Member 'LargoObjectMusic.Engine.MelodicSequence.melodicVariety' has less visibility than the enclosing method //// 'LargoObjectMusic.Engine.MelodicSequence.SequenceValue' Contract.Requires(givenVariety != null); this.melodicVariety = givenVariety; this.melodicShape = givenVariety.LineRules.MelodicShape; } #endregion #region String representation /// String representation of the object. /// Returns value. public override string ToString() { var s = new StringBuilder(); s.AppendFormat("MusicalSequence {0} {1}", this.melodicShape, this.melodicVariety); return s.ToString(); } #endregion #region Public methods /// /// Sequences the value. /// /// Returns value. public int SequenceValue() { //// Warning 5 CodeContracts: Member 'LargoObjectMusic.Engine.MelodicSequence.melodicVariety' //// has less visibility than the enclosing method 'LargoObjectMusic.Engine.MelodicSequence.SequenceValue'. Contract.Requires(this.melodicVariety.Element.Status != null); Contract.Requires(this.melodicVariety.Element.Line != null); var element = this.melodicVariety.Element; var line = (MusicalLine)element.Line; if (line.LastTone == null || line.PenultTone == null) { //// || mte.CurrentTone == null return MusicalQuantity.NeutralValue; } this.harmonicSystem = this.melodicVariety.Element.Bar.Header.System.HarmonicSystem; //// ?? mte.CurrentTone.Pitch.HarmonicSystem; var value = 0; //// Melodic shape rules switch (this.melodicShape) { case MelodicShape.MinimumMotion: { value = this.MinimumMotionValue(); break; } case MelodicShape.Scales: { value = this.ScalesValue(); break; } case MelodicShape.Sinusoids: { value = this.SinusoidsValue(); break; } case MelodicShape.BreakingLine: { value = this.BreakingLineValue(); break; } case MelodicShape.Original: break; case MelodicShape.None: break; } return value; } #endregion #region Private methods - Part related values /// Property that is higher for smaller changes of the musical pitch. /// Returns value. private int MinimumMotionValue() { var mte = this.melodicVariety.Element; if (!this.melodicVariety.Element.Status.IsFilling) { return MusicalQuantity.NeutralValue; } if (mte.Status.CurrentMelInterval == null) { return MusicalQuantity.NeutralValue; } var val = mte.Status.CurrentMelInterval.MinimumMotion; if (val < DefaultValue.HalfUnit) { //// 2008/12 VeryNiceValue caused tone duplicates in parallel voices return (int)((float)MusicalQuantity.VeryNiceValue / 2 * (1 - val)); } //// 1.0-r return MusicalQuantity.NeutralValue; // PoorValue; } /// Value of breaking line property. /// Returns value. private int BreakingLineValue() { var element = this.melodicVariety.Element; var line = (MusicalLine)element.Line; var p1 = line.PenultTone.Pitch; var p2 = line.LastTone.Pitch; if (p1 == null || p2 == null) { return MusicalQuantity.NeutralValue; } //// not more than 2 intervals (after jumping the best move in the opposite direction) var i1 = line.LastTone.Pitch.IntervalFrom(p1); var i2 = line.CurrentTone.Pitch.IntervalFrom(p2); var fi1 = this.harmonicSystem.FormalMedianLength(i1); var fi2 = this.harmonicSystem.FormalMedianLength(i2); if (fi1 == 0 && fi2 == 0) { //// if (fi2 == 0) { return MusicalQuantity.PoorValue; } //// int sum = i1 + i2; //// sum = sum > -short.MinValue ? Math.Abs(sum) : 0; int result; if (i1 >= this.harmonicSystem.Median) { result = i2 >= this.harmonicSystem.Median ? MusicalQuantity.PoorValue : Math.Sign(i1) == Math.Sign(i2) ? MusicalQuantity.GoodValue : MusicalQuantity.NiceValue; } else { result = Math.Sign(i1) == Math.Sign(i2) ? MusicalQuantity.NiceValue : MusicalQuantity.GoodValue; } return result; } /// /// Value of scales. /// /// Returns value. private int ScalesValue() { var element = this.melodicVariety.Element; var line = (MusicalLine)element.Line; if (line.LastTone?.Pitch == null) { return MusicalQuantity.NeutralValue; } //// small intervals in the same direction favored var i1 = line.LastTone.Pitch.IntervalFrom(line.PenultTone.Pitch); var i2 = line.CurrentTone.Pitch.IntervalFrom(line.LastTone.Pitch); if (2 * Math.Abs(i2) > this.harmonicSystem.Median) { return MusicalQuantity.PoorValue; } var fi1 = this.harmonicSystem.FormalMedianLength(i1); var fi2 = this.harmonicSystem.FormalMedianLength(i2); if (fi1 == 0 && fi2 == 0) { //// if (fi2 == 0) { return MusicalQuantity.PoorValue; } if (2 * Math.Abs(i1) <= this.harmonicSystem.Median && Math.Sign(i1) == Math.Sign(i2)) { return MusicalQuantity.VeryNiceValue; } return MusicalQuantity.NeutralValue; } /// /// Value of sinusoids. /// /// Returns value. private int SinusoidsValue() { var element = this.melodicVariety.Element; var line = (MusicalLine)element.Line; //// if (this.harmonicSystem == null) { return MusicalQuantity.NeutralValue; } //// tones at greater interval distance with regard to the tones in previous bars are favored. var tone1 = element.PreviousBarFirstTone; var tone2 = line.CurrentTone; if (tone1 == null || tone2 == null) { return MusicalQuantity.NeutralValue; } var d1 = tone2.Pitch.DistanceFrom(tone1.Pitch); return d1 > this.harmonicSystem.Median ? MusicalQuantity.NiceValue : MusicalQuantity.NeutralValue; } #endregion } }